﻿/**
 * jQuery twiDataTable plugin
 * @author: feitianxinhong  http://xuzhihong1987.blog.163.com/
 * @version 1.2.3
 * @create date:2014-10-25
 * @copyright (c) 2014 feitianxinhong/tyingsoft/twilight  http://www.tyingsoft.com
 * @example Visit 
 * @Require: bootstrap-3.2.0样式 
 *
 * ------------------------------------------------------------------
 * 编号    版本号      作者              修改日期        修改内容
 * ------------------------------------------------------------------
 *  1      1.0.0       feitianxinhong    2014-10-17     创建文件
 *  2      2.0.0(分支) feitianxinhong    2014-10-17    【暂时作废停滞】 checkbox使用iCheck  
 *  3      1.1.0       feitianxinhong    2014-10-24     增加了选择框来支持多选、增加了部分方法
 *  4      1.1.1       feitianxinhong    2014-10-25     增加了高度配置，滚动效果
 *  5      1.2.0       feitianxinhong    2014-10-27     增加了可配置tbar,支持皮肤skin配置
 *  6      1.2.1       feitianxinhong    2015-01-04     增加支持renderer、format，支持单行移位操作：至顶部（rowDownToFirst）、上移（rowUp）、下移（rowDown）、至底部（rowDownToLast）
 *  7      1.2.2       feitianxinhong    2015-01-06     增加列配置事件：cellclick，移位操作支持多选rowDownToFirst、rowUp、rowDown、rowDownToLast。editData方法修正
 *  8      1.2.3       feitianxinhong    2015-01-08     增加showMoveRowGroup配置来支持内置tbar显示 
 * ------------------------------------------------------------------
 */


(function ($) {
    var global = this;
    if (typeof Twi === 'undefined') {
        global.Twi = {
            emptyFn: function () { }
        };
    }
    Twi.global = global;

    /**
     * config配置说明：
     *
     * idField:      '主键或唯一字段',
     * title:        '标题',
     * skin:         '表格皮肤：'default,primary,success,info,warning,danger',
     * columns:[{
     *    text:      '表头标题【必填】',
     *    fieldName: '对应字段【必填】',
     *    dataType:  '数据类型，不填为字符串',
     *    width:     '列宽，不填则为自动',
     *    renderer:  '显示格式转换函数'【1.2.1+】,
     *    format:    '预定义数据格式，即使用内置的renderer函数,如：bool使用“√ ×”表示' 【1.2.1+】,
     *    cellclick: '单元格点击事件【1.2.2+】，参数args： 
     *                   1、tableSelf: Twi.DataTable对象，
     *                   2、rowData: 行数据,
     *                   3、rowIndex: 行索引,
     *                   4、colData: 列数据,
     *                   5、configColIndex: 数据列在配置columns的索引,
     *                   6、colFieldName: 列fieldName'
     *  }],
     * width:        'grid宽度，数字',
     * height:       'grid高度，数字',
     * renderTo:     '表格呈现的位置，默认为body，如果为id，则格式为：#id',
     * rownumberer:  '配置是否显示行号列，默认显示，如果为false时，不显示，可配置宽度width,默认为20px',
     * striped:      '是否隔行变色，default：true' , 
     * multiSelect:  '是否支持多选，default：false 【多选时，会自动显示checkbox列】',
     * checkBoxCol:  '配置是否显示选择框列,default：false，可配置宽度，默认为20px.',
     * toolbar:[{      
     *    xtype:''   '工具栏项类型:button、html' 
     *    
     * }],
     * showMoveRowGroup： '是否在底部工具栏中显示移动行按钮组，default：false'【1.2.3+】 
     *
     * 事件配置说明： 
     *         1、事件名做为config配置时，需加前缀on，如事件rowclick，配置时为onrowclick
     *         2、事件名全部为小写 【Sencha Extjs 事件特殊命名规则】
     *
     * ---------------------------------------------------------------
     *
     * config中会在内容自动处理的属性（即使配置也会被重写）【私有属性，勿赋值】：
     *
     * config._showRowNumber:  '是否显示行号',
     * config._showCheckBox:   '是否显示选择框列',
     * config._showToolbar:    '是否显示工具栏'
     * config._showBbar:       '是否显示底部工具栏'  【1.2.3+】   Bbar：BottomToolbar
     *
     * ----------------------------------------------------------------
     *
     * 属性说明:  
     * 
     *
     * 私有变量为下划线为前缀：
     *
     * _headHtml:'',             //Table表头HTML
     * _data：[],                //数组，本地的数据存储
     * _colFormat:[],            //预定义数据格式，函数集合。可扩展至columns.format使用。【1.2.1+】
     * _handlers:[],             //事件集合
     * _idFieldValues:[]         //idField对应值集合
     * 
     * ----------------------------------------------------------------
     * 
     * 事件说明：
     * rowclick(args)
     *     参数说明： 
     *              1、tableSelf : Twi.DataTable对象
     *              2、rowData:    行数据对象
     *              3、rowIndex：  行索引
     * 
     * ----------------------------------------------------------------
     * 方法说明：
     * getId：                获取Id
     * getData：              获取数据源数据 【1.2.1+】
     * editData：             修改选中行的数据【1.2.1+】 【1.2.2+ bugger修正】 
     * refresh：              刷新【1.2.1+】
     * getLastSelected：      获取最后选择行信息【仅限单选模式有效,多选请使用getSelections()】
     * getSelections：        获取选择的集合
     * getLastSelectedIndex： 获取最后选择行索引【仅限单选模式有效,多选请使用getSelectionsIndex()】【1.2.1+】
     * getSelectionsIndex:    获取选择的集合的索引 【1.2.1+】
     * selectAll:             选择所有行
     * unSelectAll:           取消选择所有行
     * checkedByKeyValue：    根据键值对选中行【可能会选中多行】
     * checkedById：          根据idField的值选中行【如果idField未配置无效,由于默认idField唯一，所以只会选择第一个】
     * checkedByIndex：       根据索引选中行
     * rowUp：                选择行向上移动 【1.2.1+】 【1.2.2+ 支持多选】 
     * rowDown：              选择行向下移动 【1.2.1+】 【1.2.2+ 支持多选】
     * rowUpToFirst：         选择行向上移动至最顶部（第一个元素的位置）   【1.2.1+】【1.2.2+ 支持多选】
     * rowDownToLast：        选择行向上移动至最底部（最后一个元素的位置） 【1.2.1+】【1.2.2+ 支持多选】
     * addColFormat：         扩展添加预定义数据格式，列数据显示格式 columns.format【1.2.1+】
     * getColFormat：         获取预定义数据格式函数  【1.2.1+】
     * addListener/on:        添加事件
     * removeListener/un/off: 移除事件
     * fireEvent:             触发事件
     *
     *
     *
     * ----------------------------------------------------------------
     */


    Twi.DataTable = function (config) {
        var me = this;
        /**
         *默认配置项 
         */
        me.defaults = {
            renderTo: 'body',
            rownumberer: {
                text:'',
                width: 20
            },
            columns: [],
            striped: true,
            multiSelect: false
        };
        /**
         * 事件
         */
        me._handlers = {};

        config = config || {};
        config = $.extend({}, me.defaults, config);

        //是否需要显示行号
        config._showRowNumber = true;
        if (typeof config.rownumberer == 'boolean') {
            if (!config.rownumberer) {
                config._showRowNumber = false;
            }
            else {
                config.rownumberer = me.defaults.rownumberer; 
            }
        }

        /*选择框列*/
        config._showCheckBox = false;
        if (typeof config.checkBoxCol == 'boolean') {
            //多选时，会强制显示checkbox列
            if(config.checkBoxCol || config.multiSelect){ 
                config._showCheckBox = true;
                config.checkBoxCol = {
                    width:20
                };
            }
        }
        else if (typeof config.checkBoxCol == 'object') {
            config._showCheckBox = true;
            config.checkBoxCol.width = config.checkBoxCol.width || 20;  //列宽默认20px
        }
        else if (typeof config.checkBoxCol == 'undefined') {
            //多选时，会强制显示checkbox列
            if (config.multiSelect) {
                config._showCheckBox = true;
                config.checkBoxCol = {
                    width: 20
                };
            }
        }

        /*属性赋值*/
        me.config = config;
        me.frameId = "TwiDtPanel" + Math.floor(10000 * Math.random());
        me.id = "TwiDataTable" + Math.floor(10000 * Math.random()); //随机ID         
        me.titleId = "TwiDtTitle" + Math.floor(10000 * Math.random());        
        me._idFieldValues = [];
        me._data = [];

        /**
         *生成title标题HTML
         */
        function getTitleHtml() {
            var titleHtml = '';
            if (config.title) {
                titleHtml = '<div id="' + me.titleId + '" class="panel-heading">' + config.title + '</div>';               
            }
            return titleHtml;
        }

        /**
         * 底部工具栏 BottomToolbar
         */
        me.Bbar = {
            /**
             * 初始化底部工具栏
             */
            init: function () {
                if (!me.config._showBbar) return;
                if (me.config.showMoveRowGroup) {
                    me.Bbar.addMoveRowGroup();
                }

            }//end init

            /**
             * 添加移动行按钮组
             */
            , addMoveRowGroup: function () {
                if (!me.config.showMoveRowGroup) return;
                me.Bbar.addItem({
                    xtype: 'btnGroup',
                    children:
                    [{
                        text: '至顶部',
                        iconCls: 'glyphicon-hand-up',
                        handler: function () {
                            me.rowUpToFirst();
                        }
                    }, {
                        text: '上移',
                        iconCls: 'glyphicon-arrow-up',
                        handler: function () {
                            me.rowUp();
                        }
                    }, {
                        text: '下移',
                        iconCls: 'glyphicon-arrow-down',
                        handler: function () {
                            me.rowDown();
                        }
                    }, {
                        text: '至底部',
                        iconCls: 'glyphicon-hand-down',
                        handler: function () {
                            me.rowDownToLast();
                        }
                    }]
                });
            }

            /**
             * 添加底部工具栏项
             * {
             *     xtype:     '类型：button、btnGroup;default:button',
             *     text：     '显示的文字,如：新增、编辑、删除、修改...',
             *     skin:      '皮肤：'default,primary,success,info,warning,danger',
             *     iconCls:   'bootstrap的图标，如：glyphicon-plus',
             *     iconColor: '颜色值：#dd5a43，red',
             *     eventType: '事件类型，default:click',
             *     handler:   '点击事件'
             *     children:[{   //当xtype为btnGroup的时候需要配置子项
             *          //配置和父级点相同，但是不能是btnGroup。
             *          //特别说明：btnGroup下配置的children的xtype都为button，配置xtype可省略
             *     }]
             * }
             *
             */
            , addItem: function (item) {
                if (item instanceof Array) {
                    for (var i = 0; i < item.length; i++) {
                        me.Bbar.addItem(item[i]);
                    }                  
                }
                else if (typeof item == 'object') {
                    item.xtype = item.xtype || 'button';
                    item.skin = item.skin || 'default';
                    item.skin = item.skin == 'default' ? '' : 'btn-' + item.skin;
                    /*按钮*/
                    if (item.xtype == 'button') {
                        var btnId = "TwiBbarItm" + Math.floor(10000 * Math.random());
                        var html = '';
                        html += '<button id="' + btnId + '" type="button" class="btn btn-default ' + item.skin + ' btn-sm">';
                        item.iconCls = item.iconCls || '';
                        html += '<span class="glyphicon ' + item.iconCls + '"></span>';
                        html += '<span class="auto-hidden">' + item.text + '</span>';
                        html += '</button>';
                        $('#' + me.frameId).children('.panel-body').children('div[twifor="bbar"]').append(html);

                        //图标颜色
                        if (typeof item.iconColor == 'string') {
                            $('#' + btnId).children('.glyphicon').css('color', item.iconColor);
                        }

                        //注册事件
                        if (typeof item.handler == 'function') {
                            item.eventType = item.eventType || 'click';
                            $('#' + btnId).off(item.eventType).on(item.eventType, item.handler);
                        }
                    }
                    /*按钮组*/
                    else if (item.xtype == 'btnGroup') {
                        if (!(item.children instanceof Array)) return;
                        var btnGroupId = "TwiBbarGroupItm" + Math.floor(10000 * Math.random());
                        var btnIDs = []; //按钮ID数组                    
                        var html = '';
                        html += '<div class="btn-group btn-group-sm">';
                        for (var i = 0; i < item.children.length; i++) {
                            var btnId = "TwiBbarItm" + Math.floor(10000 * Math.random());
                            btnIDs.push(btnId);
                            var childrenItem = item.children[i];
                            childrenItem.skin = childrenItem.skin || 'default';
                            childrenItem.skin = childrenItem.skin == 'default' ? '' : 'btn-' + childrenItem.skin;
                            html += '<button id="' + btnId + '" type="button" class="btn btn-default ' + childrenItem.skin + ' btn-sm">';
                            childrenItem.iconCls = childrenItem.iconCls || '';
                            html += '<span class="glyphicon ' + childrenItem.iconCls + '"></span>';
                            html += '<span class="auto-hidden">' + childrenItem.text + '</span>';
                            html += '</button>';
                        }
                        html += '</div>';
                        $('#' + me.frameId).children('.panel-body').children('div[twifor="bbar"]').append(html);

                        for (var i = 0; i < item.children.length; i++) {
                            var childrenItem = item.children[i];
                            //图标颜色
                            if (typeof childrenItem.iconColor == 'string') {
                                $('#' + btnIDs[i]).children('.glyphicon').css('color', childrenItem.iconColor);
                            }

                            //注册事件
                            if (typeof childrenItem.handler == 'function') {
                                childrenItem.eventType = childrenItem.eventType || 'click';
                                $('#' + btnIDs[i]).off(childrenItem.eventType).on(childrenItem.eventType, childrenItem.handler);
                            }
                        }
                    }
                    /*文本*/
                    else if (item.xtype == 'text') {
                    }
                }

            }//end addItem

            /**
             * 判断是否需要显示底部工具栏
             */
            , needShow: function () {
                return me.config.showMoveRowGroup ? true : false;
            }//end needShowBbar

        };//end Bbar

        /*主框体*/
        var mainFrameHtml = '';
        me.config.skin = me.config.skin || 'default';
        me.config.skin = me.config.skin == 'default' ? '' : 'panel-' + me.config.skin;
        mainFrameHtml += '<div id="' + me.frameId + '" class="panel panel-default '+me.config.skin+'">';
        mainFrameHtml += getTitleHtml();
        me.config._showToolbar = false;
        if (me.config.toolbar instanceof Array) {
            //toolbar 放在panel-body中
            mainFrameHtml += '<div class="panel-body tbarBottomBorder">';
            mainFrameHtml += '<div twiFor="toolbar" class="btn-toolbar"></div>'
            mainFrameHtml += '</div>';
            me.config._showToolbar = true;
        }        
        mainFrameHtml += '<div twiFor="tableContainer" class="twiTableContainer"></div>';
        me.config._showBbar = false; //是否显示底部工具栏  【1.2.3+】   Bbar：BottomToolbar
        if (me.Bbar.needShow()) {
            //toolbar 放在panel-body中
            mainFrameHtml += '<div class="panel-body bbarTopBorder">';
            mainFrameHtml += '<div twiFor="bbar" class="btn-toolbar"></div>'
            mainFrameHtml += '</div>';
            me.config._showBbar = true;
        }
        mainFrameHtml += '</div>';
        $(config.renderTo).append(mainFrameHtml);        

        //宽度设置
        if (typeof me.config.width == 'number') {
            $('#' + me.frameId).css('width', me.config.width);
        }

        //初始化底部工具栏
        me.Bbar.init();

        /**
         * 工具栏操作
         */
        me.Toolbar = {
            /**
             * 初始化工具栏
             */
            init: function () {
                if (!me.config._showToolbar) return;
                me.Toolbar.addItem(me.config.toolbar);                
            } //end init

            /**
             * 清空工具栏
             */
            , clear: function () {
                var me = this;
                if (me.config.tbar instanceof Array) {

                }
            }//end clear

            /**
             * 添加工具栏项
             * {
             *     xtype:     '类型：button、btnGroup;default:button',
             *     text：     '显示的文字,如：新增、编辑、删除、修改...',
             *     skin:      '皮肤：'default,primary,success,info,warning,danger',
             *     iconCls:   'bootstrap的图标，如：glyphicon-plus',
             *     iconColor: '颜色值：#dd5a43，red',
             *     eventType: '事件类型，default:click',
             *     handler:   '点击事件'
             *     children:[{   //当xtype为btnGroup的时候需要配置子项
             *          //配置和父级点相同，但是不能是btnGroup。
             *          //特别说明：btnGroup下配置的children的xtype都为button，配置xtype可省略
             *     }]
             * }
             *
             */
            , addItem: function (item) {
                if (item instanceof Array) {
                    for (var i = 0; i < item.length; i++) {
                        me.Toolbar.addItem(item[i]);
                    }                  
                }
                else if (typeof item == 'object') {
                    item.xtype = item.xtype || 'button';
                    item.skin = item.skin || 'default';
                    item.skin = item.skin == 'default' ? '' : 'btn-' + item.skin;
                    /*Toolbar按钮*/
                    if (item.xtype == 'button') {
                        var btnId = "TwiTbarItm" + Math.floor(10000 * Math.random()); 
                        var html = '';
                        html += '<button id="'+btnId+'" type="button" class="btn btn-default '+item.skin+' btn-sm">';
                        item.iconCls = item.iconCls || '';
                        html += '<span class="glyphicon '+item.iconCls+'"></span>';
                        html += '<span class="auto-hidden">' + item.text + '</span>';
                        html += '</button>';
                        $('#' + me.frameId).children('.panel-body').children('div[twifor="toolbar"]').append(html);

                        //图标颜色
                        if (typeof item.iconColor == 'string') {
                            $('#' + btnId).children('.glyphicon').css('color', item.iconColor);
                        }

                        //注册事件
                        if (typeof item.handler == 'function') {
                            item.eventType = item.eventType || 'click';
                            $('#' + btnId).off(item.eventType).on(item.eventType, item.handler);
                        }
                    }
                    /*Toolbar按钮组*/
                    else if (item.xtype == 'btnGroup') {
                        if (!(item.children instanceof Array)) return;
                        var btnGroupId = "TwiTbarGroupItm" + Math.floor(10000 * Math.random());
                        var btnIDs = []; //按钮ID数组                    
                        var html = '';
                        html += '<div class="btn-group btn-group-sm">';
                        for (var i = 0; i < item.children.length; i++) {
                            var btnId = "TwiBbarItm" + Math.floor(10000 * Math.random());
                            btnIDs.push(btnId);
                            var childrenItem = item.children[i];
                            childrenItem.skin = childrenItem.skin || 'default';
                            childrenItem.skin = childrenItem.skin == 'default' ? '' : 'btn-' + childrenItem.skin;
                            html += '<button id="' + btnId + '" type="button" class="btn btn-default ' + childrenItem.skin + ' btn-sm">';
                            childrenItem.iconCls = childrenItem.iconCls || '';
                            html += '<span class="glyphicon ' + childrenItem.iconCls + '"></span>';
                            html += '<span class="auto-hidden">' + childrenItem.text + '</span>';
                            html += '</button>';
                        }
                        html += '</div>';
                        $('#' + me.frameId).children('.panel-body').children('div[twifor="toolbar"]').append(html);

                        for (var i = 0; i < item.children.length; i++) {
                            var childrenItem = item.children[i];
                            //图标颜色
                            if (typeof childrenItem.iconColor == 'string') {
                                $('#' + btnIDs[i]).children('.glyphicon').css('color', childrenItem.iconColor);
                            }

                            //注册事件
                            if (typeof childrenItem.handler == 'function') {
                                childrenItem.eventType = childrenItem.eventType || 'click';
                                $('#' + btnIDs[i]).off(childrenItem.eventType).on(childrenItem.eventType, childrenItem.handler);
                            }
                        }
                    }
                    /*Toolbar文本*/
                    else if (item.xtype == 'text') {
                    }
                }
            }//end addItem

            /**
             * 按照传入的数据，重新加载工具栏
             */
            , reload: function (tbar) {

            }//end reload

        }; //end Toolbar

        //初始化工具栏
        me.Toolbar.init();

        /**
         * 生成head表头HTML
         */
        function getTableHeadHtml() {
            var headHtml = "";
            headHtml += '<thead>';
            headHtml += '<tr>';

            //行号列
            if (config._showRowNumber) {
                headHtml += '<th style="text-align:center;width:' + config.rownumberer.width + 'px;">' + config.rownumberer.text + '</th>';
            }

            //选择框列
            if (config._showCheckBox) {                
                headHtml += '<th style="text-align:center;width:' + config.checkBoxCol.width + 'px;">';
                headHtml += config.multiSelect ? '<input type="checkbox" twiDtChkType="all"/>' : "#";
                headHtml += '</th>';
            }

            //数据列
            for (var i = 0; i < config.columns.length; i++) {
                var col = config.columns[i];
                if (typeof col.width == 'number') {
                    headHtml += '<th style="width:' + col.width + 'px;">' + col.text + '</th>';
                }
                else {
                    headHtml += '<th>' + col.text + '</th>';
                }
            }

            headHtml += '</tr>';
            headHtml += '</thead>';
            return headHtml;
        }
        me._headHtml = getTableHeadHtml();

        /*表格*/
        var html = '';
        html += '<table id=' + me.id + ' class="table table-hover table-bordered';
        if (typeof me.config.striped == 'boolean' && me.config.striped) {
            //隔行变色
            html += ' table-striped';
        }
        html += '">';        
        html += me._headHtml;
        html += '<tbody></tbody>';
        html += '</table>';
        $('#' + me.frameId).children('div[twiFor="tableContainer"]').append(html);

        //高度设置
        if (typeof me.config.height == 'number') {
            $('#' + me.frameId).children('div[twiFor="tableContainer"]').css('height', me.config.height);
        }
        
        //注册全选和反选事件
        if (this.config._showCheckBox) {
            $('#' + me.id).children('thead').find(':checkbox[twiDtChkType="all"]').off('click').click(function () {
                if ($(this).prop('checked')) {
                    me.selectAll();
                }
                else {
                    me.unSelectAll();
                }
            });
        }
    }

    /**
     * 获取Id
     */
    Twi.DataTable.prototype.getId = function () {
        return this.id;
    }

    /**
     * 加载数据
     * @data: 【必填参数】，record对象数组，一般传twi.data
     */
    Twi.DataTable.prototype.loadData = function (data) {
        if (!(data  instanceof Array)) {
            return;
        }

        var tableSelf = this;
        var me = this;
        me._data = data;
        me._idFieldValues = [];

        //先清空数据
        $('#' + me.id).children('tbody').empty();

        /*添加数据行HTML*/
        for (var i = 0; i < data.length; i++) {
            var html = '<tr rowIndex="' + i + '">';
            //序号列
            if (me.config._showRowNumber) {
                html += '<td style="text-align:center;">' + (i + 1) + '</td>';
            }
            //数据行选择框列
            if (me.config._showCheckBox) {
                html += '<td><input type="checkbox" twiDtChkType="row"/></td>';
            }
            //数据列
            var colValue = "";
            for (var j = 0; j < me.config.columns.length; j++) {
                colValue = data[i][me.config.columns[j].fieldName];
                var colFormat = me.config.columns[j].format;
                if (colFormat && typeof colFormat == "string") {
                    colValue = me.getColFormat(colFormat)(colValue);
                }
                else if (me.config.columns[j].renderer && typeof me.config.columns[j].renderer == 'function') {
                    colValue = me.config.columns[j].renderer(colValue);
                }
                html += '<td configColIndex="' + j + '">' + colValue + '</td>';
            }
            html += '</tr>';
            $('#' + me.id).children('tbody').append(html);
            
            if (typeof me.config.idField == 'string') {
                me._idFieldValues.push(data[i][me.config.idField]);
            }
        }               

        /*行操作、选择行事件*/      
        $('#' + me.id).children('tbody').children('tr').each(function () {
            //jquery data 数据存储
            if (!$(this).data('rowIndex')) {
                $(this).data('rowIndex', $(this).attr('rowIndex'));
                $(this).data('rowData', me._data[$(this).data('rowIndex')]);
            }
        }).off('click').on('click', function () {
            //当前选择行样式
            $('#' + me.id).children('tbody').children('tr').removeClass('twiSelected');
            $(this).addClass('twiSelected');

            //如果是单选模式
            if (!me.config.multiSelect) {
                //单选时，选择行会自动勾选
                me.unSelectAll();
                $(this).find(':checkbox[twiDtChkType="row"]').prop('checked', true);      
            }         

            //自定义事件 rowclick
            me.fireEvent("rowclick", {
                tableSelf: tableSelf,               
                rowData: $(this).data('rowData'),
                rowIndex: $(this).data('rowIndex')
            });
        });

        /*如果有选择框列，注册checkbox选择和反选事件*/
        if (this.config._showCheckBox) {
            $('#' + me.id).children('tbody').find(':checkbox[twiDtChkType="row"]').off('click').click(function (event) {
                //checkbox 操作阻止事件冒泡
                event.stopPropagation();                

                if ($(this).prop('checked')) {
                    //当前选择行样式
                    $('#' + me.id).children('tbody').children('tr').removeClass('twiSelected');
                    $(this).parent().parent('tr').addClass('twiSelected');

                    if (me.config.multiSelect) {
                        var isAllSeleted = true; //是否数据行都选中了
                        $('#' + me.id).children('tbody').find(':checkbox[twiDtChkType="row"]').each(function () {
                            if (!$(this).prop('checked')) {
                                isAllSeleted = false;
                                return false;
                            }
                        });
                        $('#' + me.id).children('thead').find(':checkbox[twiDtChkType="all"]').prop('checked', isAllSeleted);
                    }
                    else {
                        //单选时，表头的checkbox不显示，只需要取消其他checkbox选择状态
                        me.unSelectAll();
                        $(this).prop('checked', true);
                    }
                }
                else {
                    //取消选择时把选择行样式去掉
                    $(this).parent().parent('tr').removeClass('twiSelected');
                    if (me.config.multiSelect) {
                        //取消全选
                        $('#' + me.id).children('thead').find(':checkbox[twiDtChkType="all"]').prop('checked', false);
                    }
                }
            });
        }


        /*单元格单击事件：cellclick*/
        for (var i = 0; i < me.config.columns.length; i++) {
            var cellclick = me.config.columns[i].cellclick;
            //如果列配置了cellclick
            if (typeof cellclick == 'function') {
                $('#' + me.id).children('tbody').children('tr').children('td[configColIndex='+i+']').off('click').on('click', function () {
                    var configColIndex = $(this).attr("configColIndex");
                    var rowData = $(this).parent("tr").data('rowData')
                    var rowIndex = $(this).parent("tr").data('rowIndex');
                    var colFieldName = me.config.columns[configColIndex].fieldName; //列字段
                    var colData = rowData[colFieldName];
                    //处理自定义单击单元格事件
                    me.config.columns[configColIndex].cellclick({
                        tableSelf: tableSelf,
                        rowData: rowData,
                        rowIndex: rowIndex,
                        colData: colData,
                        configColIndex: configColIndex,
                        colFieldName: colFieldName
                    });
                });
            }
        }

        /*单元格事件*/
        $('#' + me.id).children('tbody').children('tr').children('td').off('click').on('click', function () {
            var configColIndex = $(this).attr("configColIndex");
            var cellclick = me.config.columns[configColIndex].cellclick;
            if(typeof cellclick == 'function'){
                var rowData = $(this).parent("tr").data('rowData')
                var rowIndex = $(this).parent("tr").data('rowIndex');            
                var colFieldName = me.config.columns[configColIndex].fieldName; //列字段
                var colData = rowData[colFieldName];
                //处理自定义单击单元格事件
                cellclick({
                    tableSelf: tableSelf,
                    rowData: rowData,
                    rowIndex: rowIndex,
                    colData: colData,
                    configColIndex: configColIndex,
                    colFieldName: colFieldName
                });
            }
        });
    }

    /**
     * 修改选中行的数据【1.2.1+】
     * @newData: 【必填参数】 需要修改的键值对对象。如：{FCode:"001",FName:"xzh"}表示把选中项的FCode的值都改为"001",FName改为"xzh".
     * 注：修改后会自动刷新表格，并会选择修改前的行数据
     */
    Twi.DataTable.prototype.editData = function (newData) {
        if (!newData) return;
        var me = this;
        var selectionsIndex = me.getSelectionsIndex();
        var data = me.getData();
        for (var i = 0; i < selectionsIndex.length; i++) {
            var rowData = data[selectionsIndex[i]];
            for (j in data[selectionsIndex[i]]) {
                if (j && typeof rowData[j] != 'function') {
                    if (newData[j] || newData[j] == "") {
                        rowData[j] = newData[j];
                    }
                }
            }
        }
        //刷新表格
        me.refresh();

        //样式显示修改过的数据
        for (var i = 0; i < selectionsIndex.length; i++) {
            me.checkedByIndex(selectionsIndex[i]);
            if (me.config._showCheckBox) {
                $('#' + me.id).children('tbody').find('tr').eq(selectionsIndex[i]).addClass('twiSelected');
            }
        }
    }

    /**
     * 刷新【1.2.1+】
     */
    Twi.DataTable.prototype.refresh = function () {
        var me = this;
        me.loadData(me._data);
    }

    /**
     * 获取数据源数据 【1.2.1+】
     * @Return： 返回值 me._data：[],
     */
    Twi.DataTable.prototype.getData = function () {
        return this._data || [];
    }

    /**
     * 获取最后选择行信息【仅限单选模式有效,多选请使用getSelections()】
     * 
     */
    Twi.DataTable.prototype.getLastSelected = function () {
        var selections = this.getSelections();
        if (selections.length > 0) {
            return selections[0]
        }
        return undefined;
    }

    /**
     * 获取选择的集合
     */
    Twi.DataTable.prototype.getSelections = function () {
        var selections = [];
        //有选择框列的情况
        if (this.config._showCheckBox) {            
            $('#' + this.id).children('tbody').find(':checkbox[twiDtChkType]').each(function(){
                if ($(this).prop('checked')) {
                    selections.push($(this).parent().parent('tr').data('rowData'));
                }
            });                
        }
        else {
            //单项没有checkbox列，则通过样式选择
            $('#'+this.id).children('tbody').children('.twiSelected').each(function (index) {
                selections.push($(this).data('rowData'));
            });
        }        
        return selections;
    }

    /**
     * 获取最后选择行索引【仅限单选模式有效,多选请使用getSelectionsIndex()】
     * 【1.2.1+】
     */
    Twi.DataTable.prototype.getLastSelectedIndex = function () {
        var selections = this.getSelectionsIndex();
        if (selections.length > 0) {
            return selections[0]
        }
        return -1;
    }

    /**
     *  获取选择的集合的索引 【1.2.1+】
     */
    Twi.DataTable.prototype.getSelectionsIndex = function () {
        var selections = [];
        //有选择框列的情况
        if (this.config._showCheckBox) {
            $('#' + this.id).children('tbody').find(':checkbox[twiDtChkType]').each(function () {
                if ($(this).prop('checked')) {
                    selections.push(parseInt($(this).parent().parent('tr').data('rowIndex')));
                }
            });
        }
        else {
            //单项没有checkbox列，则通过样式选择
            $('#' + this.id).children('tbody').children('.twiSelected').each(function (index) {
                selections.push(parseInt($(this).data('rowIndex')));
            });
        }
        return selections;
    }

    /**
     * 选择所有行
     */
    Twi.DataTable.prototype.selectAll = function () {
        if (this.config._showCheckBox) {
            $('#' + this.id).find(':checkbox[twiDtChkType]').prop('checked', true);
        }
    }

    /**
     * 取消选择所有行
     */
    Twi.DataTable.prototype.unSelectAll = function () {
        if (this.config._showCheckBox) {
            $('#' + this.id).find(':checkbox[twiDtChkType]').prop('checked',false);
        }
    }

    /**
     * 根据键值对选中行【可能会选中多行】
     */
    Twi.DataTable.prototype.checkedByKeyValue = function (key, value) {
        var me = this;
        for (var i = 0; i < me._data.length; i++) {
            if (me._data[i][key] == value) {
                me.checkedByIndex(i);
            }
        }
    }

    /**
     * 根据idField的值选中行【如果idField未配置无效,由于默认idField唯一，所以只会选择第一个】
     *
     * @idFieldValue: idField对应行数据的值,
     *                     例如：rowData = {FCode:'001',FName:'xzh'},如果idField配置为FCode，则传001；
     *                     如果idField配置为FName，则传xzh。
     */
    Twi.DataTable.prototype.checkedById = function (idFieldValue) {
        var me = this;
        if (!me.config._showCheckBox || typeof me.config.idField != 'string') return;
        for (var i = 0; i < me._idFieldValues.length; i++) {
            if (me._idFieldValues[i] == idFieldValue) {
                me.checkedByIndex(i);
                break; //只会处理第一个
            }
        }
    }

    /**
     * 根据索引选中行
     */
    Twi.DataTable.prototype.checkedByIndex = function (index) {
        var me = this;
        if (!me.config.multiSelect) {
            me.unSelectAll(); //单选需取消之前的选择
        }
        if (me.config._showCheckBox) {
            $('#' + me.id).children('tbody').find(':checkbox[twiDtChkType]').eq(index).prop('checked',true);
        }
        else {
            //单选且无checkbox
            $('#' + me.id).children('tbody').children('tr').removeClass('twiSelected');
            $('#' + me.id).children('tbody').find('tr').eq(index).addClass('twiSelected');
        }
    }

    /**
     * 选择行向上移动 【1.2.1+】
     * @fn 可选的回调函数
     */
    Twi.DataTable.prototype.rowUp = function (fn) {
        var me = this;
        var sectionsIndex = me.getSelectionsIndex();
        if (sectionsIndex.length == 0 || sectionsIndex[0] < 1) {
            return; //没有选择任何项 或 选择第一项已经是最顶部，则不需要移动
        }
        for (var i = 0; i < sectionsIndex.length; i++) {
            var sltRowIndex = sectionsIndex[i];
            if (sltRowIndex > 0)  //-1或0 不需要移动了
            {
                var data = me._data;
                var dataFirst = data.slice(0, sltRowIndex - 1); //除去需要交换位置的两个元素的前部分元素
                var dataPrevious = data.slice(sltRowIndex - 1, sltRowIndex); //选择的前一个元素
                var dataSelection = data.slice(sltRowIndex, sltRowIndex + 1);
                var dataLast = data.slice(sltRowIndex + 1); ////除去需要交换位置的两个元素的后部分元素
                me._data = dataFirst.concat(dataSelection, dataPrevious, dataLast); //交换后的数据                              
            }
        }
        me.loadData(me._data);
        for (var i = 0; i < sectionsIndex.length; i++) {
            var sltRowIndex = sectionsIndex[i];
            if (sltRowIndex > 0) {
                sltRowIndex -= 1;  //移动后选中的位置会改变
            }
            me.checkedByIndex(sltRowIndex);
            if (me.config._showCheckBox) {
                $('#' + me.id).children('tbody').find('tr').eq(sltRowIndex).addClass('twiSelected');
            }            
            if (i == sectionsIndex.length - 1 && typeof fn == "function") {
                fn(); //执行回调函数
            }
        }
    }

    /**
     * 选择行向下移动 【1.2.1+】
     * @fn 可选的回调函数
     */
    Twi.DataTable.prototype.rowDown = function (fn) {
        var me = this;
        var sectionsIndex = me.getSelectionsIndex();
        if (sectionsIndex.length == 0 || sectionsIndex[sectionsIndex.length - 1] == me._data.length - 1) {
            return; //没有选择任何项 或 选择最后一项已经是最底部，则不需要移动
        }
        for (var i = sectionsIndex.length - 1; i >= 0; i--) {
            var sltRowIndex = sectionsIndex[i];
            if (sltRowIndex >= 0 && sltRowIndex < me._data.length - 1)  //-1或len-1 不需要移动了
            {
                var data = me._data;
                var dataFirst = data.slice(0, sltRowIndex); //除去需要交换位置的两个元素的前部分元素
                var dataSelection = data.slice(sltRowIndex, sltRowIndex + 1);
                var dataNext = data.slice(sltRowIndex + 1, sltRowIndex + 2); //选择的后一个元素        
                var dataLast = data.slice(sltRowIndex + 2); //除去需要交换位置的两个元素的后部分元素
                me._data = dataFirst.concat(dataNext, dataSelection, dataLast); //交换后的数据
            }
        }
        me.loadData(me._data);
        for (var i = sectionsIndex.length - 1; i >= 0; i--) {
            var sltRowIndex = sectionsIndex[i];
            if (sltRowIndex < me._data.length - 1) {
                sltRowIndex += 1;  //移动后选中的位置会改变
            }
            me.checkedByIndex(sltRowIndex);
            if (me.config._showCheckBox) {
                $('#' + me.id).children('tbody').find('tr').eq(sltRowIndex).addClass('twiSelected');
            }
            if (i == sectionsIndex.length - 1 && typeof fn == "function") {
                fn(); //执行回调函数
            }
        }
    }

    /**
     * 选择行向上移动至最顶部（第一个元素的位置） 【1.2.1+】
     * @fn 可选的回调函数
     */
    Twi.DataTable.prototype.rowUpToFirst = function (fn) {
        var me = this;
        var sectionsIndex = me.getSelectionsIndex();
        if (sectionsIndex.length == 0 || sectionsIndex[0] < 1) {
            return; //没有选择任何项 或 选择第一项已经是最顶部，则不需要移动
        }
        for (var i = 0; i < sectionsIndex.length; i++) {
            var sltRowIndex = sectionsIndex[i];
            if (sltRowIndex > 0)  //-1或0 不需要移动了
            {
                var toIndex = sltRowIndex - sectionsIndex[0]; //移动后的位置（移至）
                var data = me._data;
                if (toIndex == 0) {
                    var dataFirst = data.slice(0, sltRowIndex); //除去选择元素的前部分元素
                    var dataSelection = data.slice(sltRowIndex, sltRowIndex + 1);
                    var dataLast = data.slice(sltRowIndex + 1); //除去选择的后部分元素
                    me._data = dataSelection.concat(dataFirst, dataLast); //交换后的数据
                }
                else {
                    //从sltRowIndex位置 移动到 toIndex位置 其中：sltRowIndex > toIndex                    
                    var dataFirst = data.slice(0, toIndex);
                    var dataToIndex = data.slice(toIndex, toIndex + 1);
                    var dataMiddle = data.slice(toIndex + 1, sltRowIndex);
                    var dataSelection = data.slice(sltRowIndex, sltRowIndex + 1);
                    var dataLast = data.slice(sltRowIndex + 1); 
                    me._data = dataFirst.concat(dataSelection,dataMiddle,dataToIndex, dataLast); //交换后的数据
                }
            }
        }
        me.loadData(me._data);
        for (var i = 0; i < sectionsIndex.length; i++) {
            var sltRowIndex = sectionsIndex[i];
            sltRowIndex -= sectionsIndex[0];  //移动后选中的位置会改变            
            me.checkedByIndex(sltRowIndex);
            if (me.config._showCheckBox) {
                $('#' + me.id).children('tbody').find('tr').eq(sltRowIndex).addClass('twiSelected');
            }
            if (i == sectionsIndex.length - 1 && typeof fn == "function") {
                fn(); //执行回调函数
            }
        }
    }

    /**
     * 选择行向上移动至最底部（最后一个元素的位置） 【1.2.1+】
     * @fn 可选的回调函数
     */
    Twi.DataTable.prototype.rowDownToLast = function (fn) {
        var me = this;
        var sectionsIndex = me.getSelectionsIndex();
        if (sectionsIndex.length == 0 || sectionsIndex[sectionsIndex.length - 1] == me._data.length - 1) {
            return; //没有选择任何项 或 选择最后一项已经是最底部，则不需要移动
        }
        for (var i = sectionsIndex.length - 1; i >= 0; i--) {
            var sltRowIndex = sectionsIndex[i];
            if (sltRowIndex >= 0 && sltRowIndex < me._data.length - 1)  //-1或len-1 不需要移动了
            {
                var toIndex = sltRowIndex + ((me._data.length-1) - sectionsIndex[sectionsIndex.length - 1]); //移动后的位置（移至）
                var data = me._data;
                if (toIndex == me._data.length - 1) {
                    var dataFirst = data.slice(0, sltRowIndex); //除去选择元素的前部分元素
                    var dataSelection = data.slice(sltRowIndex, sltRowIndex + 1);
                    var dataLast = data.slice(sltRowIndex + 1); //除去选择的后部分元素
                    me._data = dataFirst.concat(dataLast, dataSelection); //交换后的数据
                }
                else {
                    //从sltRowIndex位置 移动到 toIndex位置 其中：sltRowIndex < toIndex                    
                    var dataFirst = data.slice(0, sltRowIndex);
                    var dataSelection = data.slice(sltRowIndex, sltRowIndex + 1);
                    var dataMiddle = data.slice(sltRowIndex + 1, toIndex);
                    var dataToIndex = data.slice(toIndex, toIndex + 1);
                    var dataLast = data.slice(toIndex + 1);
                    me._data = dataFirst.concat(dataToIndex, dataMiddle, dataSelection, dataLast); //交换后的数据
                }
            }
        }
        me.loadData(me._data);
        for (var i = sectionsIndex.length - 1; i >= 0; i--) {
            var sltRowIndex = sectionsIndex[i];
            if (sltRowIndex < me._data.length - 1) {
                sltRowIndex += (me._data.length - 1) - sectionsIndex[sectionsIndex.length - 1];  //移动后选中的位置会改变
            }
            me.checkedByIndex(sltRowIndex);
            if (me.config._showCheckBox) {
                $('#' + me.id).children('tbody').find('tr').eq(sltRowIndex).addClass('twiSelected');
            }
            if (i == sectionsIndex.length - 1 && typeof fn == "function") {
                fn(); //执行回调函数
            }
        }
    }

    /**
     * 扩展添加预定义数据格式，列数据显示格式 columns.format【1.2.1+】
     * @formatName:格式名
     * @fn:处理函数(传入参数为value)
     */
    Twi.DataTable.prototype.addColFormat = function(formatName,fn){
        if(typeof fn !='function') return ;
        var me = this;
        me._colFormat = me._colFormat  instanceof Array ? me._colFormat : [];
        me._colFormat[formatName] = []; //如果有则，移除之前的
        me._colFormat[formatName].push(fn);
    }

    /**
     * 获取预定义数据格式  【1.2.1+】
     * @formatName:格式名，如bool
     */
    Twi.DataTable.prototype.getColFormat = function(formatName){
        var me = this;
        me._colFormat = me._colFormat  instanceof Array ? me._colFormat : [];
        if(typeof me._colFormat[formatName] != 'undefined'){
            return me._colFormat[formatName][0];            
        }
        else if(formatName == "bool"){
            me.addColFormat("bool",function(value){
                if(typeof value == "string"){
                    if(value == "1"){
                        return '<span style="color:green;">√</span>';
                    }
                    else if(value == "0"){
                        return '×';
                    }
                    return value;
                }
                else if (typeof value == "boolean") {
                    return value ? '<span style="color:green;">√</span>' : '×';
                }
                return value;
            });
            return me._colFormat[formatName][0]; 
        }
        else{
            return function(value){
                return value;
            }
        }
    }

    /**
     * 添加事件
     */
    Twi.DataTable.prototype.addListener = function (eventName, fn) {
        if (typeof this._handlers[eventName] == 'undefined') {
            this._handlers[eventName] = [];
        }
        if (typeof fn == "function") {
            this._handlers[eventName].push(fn);
        }
    }
    Twi.DataTable.prototype.on = Twi.DataTable.prototype.addListener;

    /**
     * 移除事件
     */
    Twi.DataTable.prototype.removeListener = function (eventName) {
        if (this._handlers[eventName] instanceof Array) {
            this._handlers[eventName] = undefined;
        }
    }
    Twi.DataTable.prototype.un = Twi.DataTable.prototype.off = Twi.DataTable.prototype.removeListener;

    /**
     * 触发事件
     * @eventName: 事件名称
     * @args: 参数对象
     */
    Twi.DataTable.prototype.fireEvent = function (eventName, args) {
        args = args || {};
        if (this._handlers[eventName] instanceof Array) {
            var fns = this._handlers[eventName];
            for (var i = 0; i < fns.length; i++) {
                fns[i](args);
            }
        }
    }

})(window.jQuery);

